#include <iostream>
#include <vector>
#include <cstdint>
#include <functional>
#include <memory>
#include <unordered_map>

using namespace std;

using destroy_func_t = function<void()>;
using release_func_t = destroy_func_t;


class timer_task {
public:
    timer_task(uint64_t id, uint32_t delay, const destroy_func_t &cb) 
        : _id(id), _timeout(delay), _cancelled(false), _destroy_cb_(cb) 
    {}

    uint32_t get_timeout() const {
        return _timeout;
    }

    void set_release_cb(const release_func_t &cb) {
        _release_cb = cb;
    }

    void cancel_task() {
        _cancelled = true;
    }

    ~timer_task() {
        // 只有被没被取消才销毁
        if(!_cancelled) {
            _destroy_cb_();
            _release_cb();
        }
        
    }
private:
    // 每一个定时器任务得有表示唯一标识id
    // 由于服务器是一直运行的，可能有很多的任务，所以uint64_t
    // 尽量由系统统一分配
    uint64_t _id;
    // 更新超时时间的基准值
    uint32_t _timeout;
    // 任务是否被取消
    bool _cancelled;
    // 定时器要执行的销毁任务
    destroy_func_t _destroy_cb_;
    release_func_t _release_cb;
};


class time_wheel {
    using task_sptr = shared_ptr<timer_task>;
    using task_wptr = weak_ptr<timer_task>;

public:
    time_wheel() 
        :_tick_idx(0), _wheel_capacity(60), _wheel(_wheel_capacity) 
    {}

    void add_task(uint64_t id, uint32_t timeout, const destroy_func_t &cb) {
        task_sptr tp = make_shared<timer_task>(id, timeout, cb);
        tp->set_release_cb(bind(&time_wheel::remove_task, this, id));
        int pos = (_tick_idx + timeout) % _wheel_capacity;
        _wheel[pos].push_back(tp);
        _tasks[id] = task_wptr(tp);
    }

    void remove_task(uint64_t id) {
        if(_tasks.count(id) == 0) {
            // 任务不存在
            return;
        }
        _tasks.erase(id);
    }

     void task_refresh(uint64_t id) {
        if(_tasks.count(id) == 0) {
            // 任务不存在
            return;
        }
        task_sptr task = _tasks[id].lock();
        uint32_t new_pos = (_tick_idx + task->get_timeout()) % _wheel_capacity;
        _wheel[new_pos].push_back(task);
    }

    void set_task_cancel(uint64_t id) {
        if(_tasks.count(id) == 0) {
            // 任务不存在
            return;
        }
        task_sptr task = _tasks[id].lock();
        task->cancel_task();
    }

    void tick() {
        _tick_idx = (_tick_idx + 1) % _wheel_capacity;
        _wheel[_tick_idx].clear();
    }
private:
    // 秒针，走到哪里就执行哪里的销毁任务
    int _tick_idx;
    // 秒盘最大刻度
    int _wheel_capacity;
    // 时间轮 
    vector<vector<task_sptr>> _wheel;
    // 用来存放时间轮中的定时器对象信息，当执行销毁任务后需要把相应的对象从中移除
    // 注意这里必须有weak_ptr，否则它会影响时间轮中任务对象生命周期，进而导致引用计数减不到0
    // 无法执行销毁任务
    unordered_map<uint64_t, task_wptr> _tasks;
};
